#!/usr/bin/python
"""
/* sudoku_main.py - sudoku puzzle UI game
 *
 * Copyright 2009
 * Authored by Erin Yueh <erinyueh@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 */
""" 

import ecore.evas
import ecore
import edje
import random
from sudoku import generator

SCREEN_GEOMETRY = (480, 640)
GROUP_ROWCOL = {
                '0': (0,0,0), '1':(1,0,3), '2':(2,0,6),
                '3': (3,3,0), '4':(4,3,3), '5':(5,3,6),
                '6': (6,6,0), '7':(7,6,3), '8':(8,6,6),
               }
THEME = "/usr/share/om-sudoku/sudoku_new.edj"

def main():

    global ee
    w, h = SCREEN_GEOMETRY
    ee = ecore.evas.SoftwareX11(w=w, h=h)
    ee.title_set('Sudoku')
    ee.size_min_set(w,h)
    ee.size_max_set(w,h)
    canvas = ee.evas

    # create a background
    bg = edje.Edje(canvas, file=THEME, group="sudoku/icon")
    bg.signal_callback_add("mouse,clicked,*", "*", icon_clicked_cb)
    bg.pos = (0, 0)
    bg.size = canvas.size
    ee.data["bg"] = bg
    bg.show()

    # retrieve one puzzle data
    puzzle = get_puzzle()
    puzzle_clone = []
    for i in xrange(9):
        row = []
        for j in xrange(9):
            row.append(puzzle[i][j])
        puzzle_clone.append(row)

    ee.data["puzzle"] = puzzle
    ee.data["puzzle_clone"] = puzzle_clone
    ee.data["clicking"] = None

    # init redo undo track
    ee.data["undo_counter"] = 0
    ee.data["redo_counter"] = 0
    ee.data["undo_track"] = []
    ee.data["redo_track"] = []
    
    # create puzzle board
    for i in xrange (9):
        for j in xrange(9):
            # aware of xy position
            x = 40 + (50 * (i))
            y = 25 + (50 * (j))
            addr = j *9 + i
            if(addr%2==0):
                emission_name = "emit,even"
            elif(addr%2==1):
                emission_name = "emit,odd"
            
            grid = edje.Edje(canvas, file=THEME, group="sudoku/grid")
            grid.center = (x,y)
            text = edje.Edje(canvas, file=THEME, group="sudoku/text")
            text.center = (x,y)
            text.part_text_set("value",str(puzzle[j][i]))
            if puzzle[j][i] == 0:
                text.part_text_set("value","")
            text.show()
            if int(puzzle[j][i]) == 0:
                grid.signal_callback_add("mouse,clicked,*", "*", grid_key_cb)
            grid.data["addr"] = int(addr)
            grid.data["text"] = text
            grid.signal_emit(emission_name,"rect")
            grid.show()
            ee.data[addr] = grid

    # create number keyboard
    for i in xrange (0,3):
        for j in xrange(1,4):
            key = (i*3)+j
            # aware of xy position
            (x,y) = (280 + 50*j, 470 + 50*i)
            if(key%2==0):
                name = "emit,even"
            elif(key%2==1):
                name = "emit,odd"
            obj = edje.Edje(canvas, file=THEME, group="sudoku/numberkey")
            obj.center = (x,y)
            obj.part_text_set("text",str(key))
            obj.signal_emit(name,"key")
            obj.signal_callback_add("mouse,clicked,*", "*", number_key_cb)
            obj.show()

    # create group lines
    for v in xrange(0,2):
        for h in xrange(0,2):
            line = edje.Edje(canvas, file=THEME, group="sudoku/group_line")
            # aware of xy position
            if(v==0):
                (x,y) = (h*150+163,0)
                line.signal_emit("emit,vertical","line")
            else:
                (x,y) = (15,150*h+150)
                line.signal_emit("emit,horizontal","line")
            line.pos = (x,y)
            line.show()

    # display a focus
    focus = edje.Edje(canvas, file="/usr/share/pyefl-sudoku/sudoku_new.edj", group="sudoku/focus")
    ee.data["focus"] = focus
    
    ee.callback_resize_set(resize_cb)
    ee.callback_delete_request_set(delete_request_cb)
    ee.show()
    ecore.main_loop_begin()

def resize_cb(ee):
    return True

def delete_request_cb(ee):
    ecore.main_loop_quit()
    return True

def grid_key_cb(grid, emission, source):
    #print 'grid_key_cb',grid,emission,source
    ee.data["clicking"] = int(grid.data["addr"])
    # display focus
    focus = ee.data["focus"]
    focus.stack_above(grid)
    (x,y) = getButtonPos(int(grid.data["addr"]))
    focus.center = (x,y)
    focus.show()
    return True

def number_key_cb(key, emission, source):
    #print 'number_key_cb',key,emission,source
    number_clicked = key.part_text_get("text")
    focus = ee.data["focus"]
    if ee.data["clicking"] == None:
        return

    addr = int(ee.data["clicking"])
    i = int(addr) / 9
    j = int(addr) % 9
    grid = ee.data[addr]
    text = grid.data["text"]

    text.part_text_set("value",str(number_clicked))
    text.stack_above(grid)
    text.stack_above(focus)
    if(analyze(addr,int(number_clicked)) == False):
        text.signal_emit("emit,value_wrong","value")
    else:
        text.signal_emit("emit,value_correct","value")

    # real fill in the value to puzzle data
    puzzle = ee.data["puzzle"]
    puzzle[i][j] = int(number_clicked)
    # record the step
    undo_counter = ee.data["undo_counter"]
    ee.data["undo_counter"] = undo_counter +1
    step = (int(addr),int(number_clicked))
    ee.data["undo_track"].append(step)

    return True

def getButtonPos(addr):

    i = int(addr) / 9
    j = int(addr) % 9
    # aware of xy position
    x = 40 + (50 * (j))
    y = 25 + (50 * (i))

    return x,y

def get_puzzle():
    gen = generator.SudokuGenerator()
    level = random.randint(2,5)
    #print 'level',level
    new_puzzle = gen.generate_single(level)
    bg = ee.data["bg"]
    if(level==2):
        bg.part_text_set("action","Easy")
    elif(level==3):
        bg.part_text_set("action","Midium")
    elif(level==4):
        bg.part_text_set("action","Difficult")
    elif(level==5):
        bg.part_text_set("action","Super Hard")
    return new_puzzle

def checkRow(row,value):
    isOK = True
    puzzle = ee.data["puzzle"]
    if value in puzzle[row]:
        return False
    return isOK
    
def checkColumn(column,value):
    isOK = True
    puzzle = ee.data["puzzle"]
    for i in xrange(9):
        if(value == puzzle[i][column]):
            return False
    return isOK

def checkGroup(group,value):
    isOK = True
    puzzle = ee.data["puzzle"]
    (group,r,c) = GROUP_ROWCOL[str(group)]
    for i in xrange (r,r+3):
        for j in xrange(c,c+3):
            if(value == puzzle[i][j]):
                return False
    return isOK

def solve():
    isOK = True
    puzzle = ee.data["puzzle"]
    row =  [ [] for i in xrange(9)]
    column =  [ [] for i in xrange(9)]
    group =  [ [] for i in xrange(9)]
    for i in xrange (9):
        for j in xrange(9):
            value = puzzle[i][j]
            g = (i/3)*3 + (j/3)
            row[i].append(value)
            column[j].append(value)
            group[g].append(value)
    # should only display once
    for x in xrange(9):
        for v in xrange(1,10):
            if not(row[x].count(v) == 1 and column[x].count(v) ==1 and group[x].count(v) ==1):
                isOK = False

    return isOK

def analyze(addr,value):
    isOK = True
    i = int(addr) / 9
    j = int(addr) % 9
    g = (i/3)*3 + (j/3)
    if(checkRow(i,value) == False or checkColumn(j,value) == False or checkGroup(g,value) == False):
        return False

    return isOK
    
def icon_clicked_cb(icon, emission, source):
    #print 'icon_clicked_cb',icon,emission,source
    bg = ee.data["bg"]
    bg.part_text_set("action","")
    if(source == 'clear' or source == 'create'):
        # init undo redo action track
        ee.data["undo_counter"] = 0
        ee.data["redo_counter"] = 0
        ee.data["undo_track"] = []
        ee.data["redo_track"] = []
        # clear focus data
        ee.data["clicking"] = None
        focus = ee.data["focus"]
        focus.hide()
        if(source == 'clear'):
            # put the original data back
            puzzle_clone = ee.data["puzzle_clone"]
            puzzle = ee.data["puzzle"]
            for i in xrange (9):
                for j in xrange(9):
                    value = puzzle_clone[i][j]
                    puzzle[i][j] = int(value)
                    addr = j + i *9
                    grid = ee.data[addr]
                    text = grid.data["text"]
                    text.part_text_set("value",str(value))
                    if(int(value) == 0 ):
                        text.part_text_set("value","")
        elif(source == 'create'):
            createNewPuzzle()
    
    elif(source == 'solve'):
        if(solve() == False):
            bg.part_text_set("action","FAILED")
        else:
            bg.part_text_set("action","Congratulations!")

    elif(source == 'redo'):
        if(ee.data["redo_counter"] == 0):
            return
        redo_counter = ee.data["redo_counter"]
        (addr,value) = ee.data["redo_track"][redo_counter-1]
        undo = ee.data["redo_track"].pop()
        ee.data["undo_track"].append(undo)
        undo_counter = ee.data["undo_counter"]
        ee.data["undo_counter"] = undo_counter+1

        i = int(addr) / 9
        j = int(addr) % 9
        grid = ee.data[addr]
        text = grid.data["text"]
        text.part_text_set("value",str(value))
        text.signal_emit("emit,value_redo","value")
        ee.data["puzzle"][i][j] = int(value)
        if(redo_counter>0):
            ee.data["redo_counter"] = redo_counter-1

    elif(source == 'undo'):
        if(ee.data["undo_counter"] == 0):
            return

        undo_counter = ee.data["undo_counter"]
        (addr,value) = ee.data["undo_track"][undo_counter-1]
        redo = ee.data["undo_track"].pop()
        ee.data["redo_track"].append(redo)
        redo_counter = ee.data["redo_counter"]
        ee.data["redo_counter"] = redo_counter+1

        i = int(addr) / 9
        j = int(addr) % 9
        original_value = ee.data["puzzle_clone"][i][j]
        grid = ee.data[addr]
        text = grid.data["text"]
        text.part_text_set("value","")
        text.signal_emit("emit,value_undo","value")
        
        ee.data["puzzle"][i][j] = original_value
        if(undo_counter>0):
            ee.data["undo_counter"] = undo_counter-1
    return True

def createNewPuzzle():
    
    puzzle = get_puzzle()
    for i in xrange(9):
        for j in xrange(9):
            ee.data["puzzle"][i][j] = puzzle[i][j]
            ee.data["puzzle_clone"][i][j] = puzzle[i][j]
            value = puzzle[i][j]
            addr = j + i *9
            
            grid = ee.data[addr]
            text = grid.data["text"]
            text.signal_emit("emit,value_default","value")
            if(addr%2==0):
                emission_name = "emit,even"
            elif(addr%2==1):
                emission_name = "emit,odd"
            
            if(int(value) == 0 ):
                text.part_text_set("value","")
                grid.signal_callback_add("mouse,clicked,*", "*", grid_key_cb)
            else:
                text.part_text_set("value",str(value))

            grid.signal_emit(emission_name,"rect")

    return True
    
if __name__ == "__main__":
	main()